<script setup>
import { getElementSize } from '@/views/study/three/composables'
import { useResizeObserver } from '@vueuse/core'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'
import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js'
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'
import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js'

const webgl = ref(null)

let renderer = null
let camera = null
let outlinePass = null

let mesh1 = null
let mesh2 = null
let mesh3 = null

onMounted(() => {
  const { width, height } = getElementSize(webgl)

  const scene = new THREE.Scene()
  camera = new THREE.PerspectiveCamera(30, width / height, 0.1, 1000)

  camera.position.set(25, 25, 25)

  const lights = []
  lights[0] = new THREE.DirectionalLight('#FFF', 5)
  lights[1] = new THREE.DirectionalLight('#FFF', 5)
  lights[2] = new THREE.DirectionalLight('#FFF', 5)

  lights[0].position.set(0, 200, 0)
  lights[1].position.set(100, 200, 100)
  lights[2].position.set(-100, -200, -100)

  scene.add(...lights)

  const geometry = new THREE.SphereGeometry(5, 50, 50)
  const material = new THREE.MeshPhongMaterial({
    color: '#156289',
  })

  mesh1 = new THREE.Mesh(geometry, material)

  mesh2 = mesh1.clone()
  mesh2.geometry = mesh1.geometry.clone()
  mesh2.material = mesh1.material.clone()
  mesh2.position.y = 10

  mesh3 = mesh1.clone()
  mesh3.geometry = mesh1.geometry.clone()
  mesh3.material = mesh1.material.clone()
  mesh3.position.x = 10

  const group = new THREE.Group()
  group.add(mesh1, mesh2, mesh3)
  // 更新下模型的世界矩阵 设置的mesh.position才生效 再进行射线拾取计算
  group.updateMatrixWorld(true)

  scene.add(group)

  renderer = new THREE.WebGLRenderer()
  renderer.setSize(width, height)
  renderer.render(scene, camera)
  webgl.value.appendChild(renderer.domElement)

  const composer = new EffectComposer(renderer)

  const renderPass = new RenderPass(scene, camera)
  composer.addPass(renderPass)

  outlinePass = new OutlinePass(new THREE.Vector2(width, height), scene, camera)
  composer.addPass(outlinePass)

  // SMAAPass抗锯齿
  const pixelRatio = renderer.getPixelRatio()
  const smaaPass = new SMAAPass(width * pixelRatio, height * pixelRatio)
  composer.addPass(smaaPass)

  handleAddEventListener()

  const orbit = new OrbitControls(camera, renderer.domElement)
  orbit.enableDamping = true

  function render() {
    requestAnimationFrame(render)

    orbit.update()

    composer.render()
  }

  render()
})

function handleAddEventListener() {
  const raster = new THREE.Raycaster()

  renderer.domElement.addEventListener('click', (e) => {
    const { width, height } = getElementSize(webgl)
    const { offsetX, offsetY } = e

    // canvas画布的宽度是width，.offsetX的范围是0~width,.offsetX除以canvas画布宽度width，就可以从绝对值变成相对值，范围是0~1，相对值乘以2，范围0~2，再减去1，范围是-1~1，刚好和canvas画布标准设备坐标的范围-1~1能够对应起来
    const x = (offsetX / width) * 2 - 1
    const y = -(offsetY / height) * 2 + 1

    // 形象点说就是在点击位置创建一条射线，用来选中拾取模型对象
    raster.setFromCamera(new THREE.Vector2(x, y), camera)

    // 射线发射拾取模型对象
    const intersects = raster.intersectObjects([mesh1, mesh2, mesh3])
    if (intersects.length) {
      const color = intersects[0].object.material.color
      const c = color.equals(new THREE.Color('#FF0000')) ? '#156289' : '#FF0000'

      color.set(c)

      outlinePass.selectedObjects = [intersects[0].object]
    }
  })
}

function resizeHandler() {
  const { width, height } = getElementSize(webgl)

  camera.aspect = width / height
  camera.updateProjectionMatrix()

  renderer.setSize(width, height)
}

useResizeObserver(webgl, () => {
  resizeHandler()
})
</script>

<template>
  <div ref="webgl" />
</template>
